This post includes notes that I took from watching a presentation given by Eduardo Ariño de la, the Chief Data Scientist at Domino Data Lab. In his presentation, he introduces 23 visualizations and the appropriate scenarios to use them. You can find the presentation here, Video- 23 Visualizations and when to use them. My goal is to familiarize myself with these plots by writing the code using mainly ggplot and datasets that I am familiar with.
Load Libraries
library(tidyverse)
library(lubridate)
library(readxl)
theme_set(theme_classic())
options(scipen=999)
Loading Global Superstore Dataset
global = read_excel("global_superstore.xls", sheet = 1, col_names = T)
Data Munging
# rename variables
global = rename(global, row_id = `Row ID`, order_id = `Order ID`, order_date = `Order Date`, ship_date = `Ship Date`, ship_mode = `Ship Mode`, customer_id = `Customer ID`, customer_name = `Customer Name`, segment = Segment, city = City, state = State, country = Country, postal_code = `Postal Code`, market = Market, region = Region, product_id = `Product ID`, category = Category, sub_category = `Sub-Category`, product_name = `Product Name`, sales = Sales, quantity = Quantity, discount = `Discount`, profit = `Profit`, shipping_cost = `Shipping Cost`, order_priority = `Order Priority`)
Adding new date columns based on weekday, day, month and year.
global = global %>%
mutate(weekday = wday(order_date, label = T),
day = day(order_date),
month = month(order_date, label = T),
year = year(order_date))
global
Deviation
Deviation can be used to emphasize variation from a fixed reference point such as 0, average or any target.
diverging_profit =
global %>%
mutate(gain_loss = ifelse(profit < 0, 'loss', 'gain')) %>%
select(order_date, region, profit, gain_loss) %>%
arrange(profit)
ggplot(diverging_profit, aes(x = region, y = profit, label = profit)) +
geom_bar(stat='identity', aes(fill=gain_loss), width=.8) +
labs(title = "Diverging Bar", subtitle = "Profit loss or gain from a fixed reference point of 0")+
coord_flip()+
scale_fill_manual(values = c("gain"="#1F77B4", "loss"="#FF7F0E"))

ggplot(diverging_profit, aes(x=region, y=profit, label=profit)) +
geom_point(stat='identity', aes(colour=gain_loss), size=2, alpha = 0.6) +
labs(title = "Diverging Dot Plot",
subtitle = "Profit loss or gain from a fixed reference point of 0") +
coord_flip() + scale_colour_manual(values = c("gain"="#1F77B4", "loss"="#FF7F0E"))

filter_2012 = global %>%
mutate(gain_loss = ifelse(profit > 0, 'gain', 'loss')) %>%
filter(order_date < "2011-06-01")
ggplot(filter_2012, aes(order_date, profit, fill = gain_loss )) +
geom_area() + labs(title = "Diverging Area Chart", subtitle = "Profit loss or gain from a fixed reference point of 0") + scale_fill_manual(values = c("gain"="#1F77B4", "loss"="#FF7F0E"))

Correlation
Correlation shows the relationship between two or more variables.
ggplot(global, aes(x = sales, y = profit)) +
geom_point(aes(col = segment), alpha = 0.6) +
geom_smooth(method = "loess", se = F) +
labs(title = "Scatterplot with Smoothing Line Based on LOESS", subtitle = "Sales vs Profit") +
scale_colour_manual(values = c("#1F77B4","#FF7F0E", "#2CA02C"))

Loading fuel economy data from 1999 and 2008 for 38 popular models of car
mpg
ggplot(mpg, aes(x = hwy, y = displ)) +
geom_point(colour = "#FF7F0E")+
geom_smooth(method = "loess", se = F) +
labs(title = "Scatterplot with Smoothing Line Based on LOESS", subtitle = "Engine Displacement vs Highway Miles Per Gallon")

Ranking
Ranking is useful where ordered list is important.
ranked_region =
global %>%
select(region, sales)%>%
group_by(region) %>%
summarise(sum = sum(sales)) %>%
mutate(region = factor(region, levels = region[order(sum, decreasing = TRUE)]))
ggplot(ranked_region, aes(x = region, y = sum)) +
geom_bar(stat = "identity", width = .8, fill = "#1F77B4")+
theme(axis.text.x = element_text(angle=65, vjust=0.6)) +
labs(title = "Ranked Bar Chart", subtitle = "Sales by Region")

NA
ggplot(ranked_region, aes(x = region, y = sum)) +
geom_point(size = 3, col = "#1F77B4", alpha = 0.9)+
geom_segment(aes(x = region,
xend = region,
y = min(sum),
yend = max(sum)),
linetype = "dashed",
size = 0.1) +
labs(title = "Dot Plot Ranking Bar", subtitle = "Sales vs Region") +
coord_flip()

Distribution
Distribution plots show how often values of a variable occur.
ggplot(mpg, aes(x = hwy)) +
geom_histogram(bins = 7,col = "black", fill = "#1F77B4") +
labs(title = "Histogram", subtitle = "Count of Highway Miles")

Data munging
mtcars$cyl = as.factor(mtcars$cyl)
mtcars
ggplot(mtcars, aes(wt)) +
geom_density(aes(fill = factor(cyl)), alpha = 0.7) + xlim(0,6)+
labs(title="Density plot",
subtitle="Weight (1000 lbs) per Cylinder",
caption="Source: mtcars",
x="Weight",
fill="Cylinders") +
scale_fill_manual(values = c("#1F77B4", "#2CA02C","#FF7F0E"))

ggplot(mtcars, aes(cyl, qsec, group = cyl)) +
geom_boxplot(varwidth = T, fill = "#1F77B4") +
labs(title="Boxplot",
subtitle="1/4 mile time per Cylinder",
caption="Source: mtcars",
x="Cylinders")

Composition
Compositions graphs show how a single entity can be broken down into its components elements.
ggplot(global, aes(sub_category)) +
geom_bar(aes(fill = category)) +
theme(axis.text.x = element_text(angle=65, vjust=0.6)) +
labs(title="Composition",
subtitle="Counts of Sub-Category - Grouped by Category",
caption="Source: Superstore",
x="Sub-Category",
fill = "Category" ) +
scale_fill_manual(values = c("#1F77B4","#FF7F0E", "#2CA02C"))

NA
global
Stacked Column
ggplot(global, aes(market)) +
geom_bar(aes(fill = category)) +
theme(axis.text.x = element_text(angle=65, vjust=0.6)) +
labs(title="Category Stacked - Bar Chart",
subtitle="Markets - Grouped by Category",
x = "Market",
fill = "Category",
caption="Source: Superstore") +
scale_fill_manual(values = c("#1F77B4","#FF7F0E", "#2CA02C"))

global_treemap = global %>%
filter(year == 2012, month == 'Jan') %>%
mutate(country = as.factor(country),
region = as.factor(region),
market = as.factor(market))
library(treemapify)
treeMapCoordinates <- treemapify(
global_treemap,
area = "sales",
fill = "profit",
group = "market")
treeMapPlot <- ggplotify(treeMapCoordinates)
print(treeMapPlot)

Change
Change gives emphasis to changing trends.
year_2012 =
global %>%
filter(year == 2012)
ggplot(year_2012, aes(order_date, sales)) +
geom_line(col = "#1F77B4") +
facet_wrap(~segment, nrow = 3) +
labs(title="Change Trends",
subtitle="Sales by segment",
x = "Date",
caption="Source: Superstore")

Heatmap - with heatmaps we can spot variations of a metric.
library(superheat)
superheat(mtcars_matrix,
left.label.size = 0.3,
left.label.text.size = 3,
legend.text.size = 12,
padding = .1)


Video - 23 Visualizations and when to use them
LS0tCnRpdGxlOiAnVmlzdWFsaXphdGlvbjogV2hlbiB0byB1c2UgdGhlbSEnCm91dHB1dDoKICBodG1sX25vdGVib29rOiBkZWZhdWx0CiAgcGRmX2RvY3VtZW50OiBkZWZhdWx0Ci0tLQoKVGhpcyBwb3N0IGluY2x1ZGVzIG5vdGVzIHRoYXQgSSB0b29rIGZyb20gd2F0Y2hpbmcgYSBwcmVzZW50YXRpb24gZ2l2ZW4gYnkgRWR1YXJkbyBBcmnDsW8gZGUgbGEsIHRoZSBDaGllZiBEYXRhIFNjaWVudGlzdCBhdCBEb21pbm8gRGF0YSBMYWIuICBJbiBoaXMgcHJlc2VudGF0aW9uLCBoZSBpbnRyb2R1Y2VzIDIzIHZpc3VhbGl6YXRpb25zIGFuZCB0aGUgYXBwcm9wcmlhdGUgc2NlbmFyaW9zIHRvIHVzZSB0aGVtLgpZb3UgY2FuIGZpbmQgdGhlIHByZXNlbnRhdGlvbiBoZXJlLCBbVmlkZW8tIDIzIFZpc3VhbGl6YXRpb25zIGFuZCB3aGVuIHRvIHVzZSB0aGVtXShodHRwczovL2Jsb2cuZG9taW5vZGF0YWxhYi5jb20vdmlkZW8tMjMtdmlzdWFsaXphdGlvbnMtdXNlLykuIE15IGdvYWwgaXMgdG8gZmFtaWxpYXJpemUgbXlzZWxmIHdpdGggdGhlc2UgcGxvdHMgYnkgd3JpdGluZyB0aGUgY29kZSB1c2luZyBtYWlubHkgZ2dwbG90IGFuZCBkYXRhc2V0cyB0aGF0IEkgYW0gZmFtaWxpYXIgd2l0aC4KCiMjI0xvYWQgTGlicmFyaWVzCmBgYHtyfQpsaWJyYXJ5KHRpZHl2ZXJzZSkKbGlicmFyeShsdWJyaWRhdGUpCmxpYnJhcnkocmVhZHhsKQp0aGVtZV9zZXQodGhlbWVfY2xhc3NpYygpKQpvcHRpb25zKHNjaXBlbj05OTkpCmBgYAojIyMjTG9hZGluZyBHbG9iYWwgU3VwZXJzdG9yZSBEYXRhc2V0CmBgYHtyfQpnbG9iYWwgPSByZWFkX2V4Y2VsKCJnbG9iYWxfc3VwZXJzdG9yZS54bHMiLCBzaGVldCA9IDEsIGNvbF9uYW1lcyA9IFQpCmBgYAoKIyMjI0RhdGEgTXVuZ2luZwpgYGB7cn0KIyByZW5hbWUgdmFyaWFibGVzCmdsb2JhbCA9IHJlbmFtZShnbG9iYWwsIHJvd19pZCA9IGBSb3cgSURgLCBvcmRlcl9pZCA9IGBPcmRlciBJRGAsIG9yZGVyX2RhdGUgPSBgT3JkZXIgRGF0ZWAsIHNoaXBfZGF0ZSA9IGBTaGlwIERhdGVgLCBzaGlwX21vZGUgPSBgU2hpcCBNb2RlYCwgY3VzdG9tZXJfaWQgPSBgQ3VzdG9tZXIgSURgLCBjdXN0b21lcl9uYW1lID0gYEN1c3RvbWVyIE5hbWVgLCBzZWdtZW50ID0gU2VnbWVudCwgY2l0eSA9IENpdHksIHN0YXRlID0gU3RhdGUsIGNvdW50cnkgPSBDb3VudHJ5LCBwb3N0YWxfY29kZSA9IGBQb3N0YWwgQ29kZWAsIG1hcmtldCA9IE1hcmtldCwgcmVnaW9uID0gUmVnaW9uLCBwcm9kdWN0X2lkID0gYFByb2R1Y3QgSURgLCBjYXRlZ29yeSA9IENhdGVnb3J5LCBzdWJfY2F0ZWdvcnkgPSBgU3ViLUNhdGVnb3J5YCwgcHJvZHVjdF9uYW1lID0gYFByb2R1Y3QgTmFtZWAsIHNhbGVzID0gU2FsZXMsIHF1YW50aXR5ID0gUXVhbnRpdHksIGRpc2NvdW50ID0gYERpc2NvdW50YCwgcHJvZml0ID0gYFByb2ZpdGAsIHNoaXBwaW5nX2Nvc3QgPSBgU2hpcHBpbmcgQ29zdGAsIG9yZGVyX3ByaW9yaXR5ID0gYE9yZGVyIFByaW9yaXR5YCkKYGBgCiMjIyMgQWRkaW5nIG5ldyBkYXRlIGNvbHVtbnMgYmFzZWQgb24gd2Vla2RheSwgZGF5LCBtb250aCBhbmQgeWVhci4KYGBge3J9Cmdsb2JhbCA9IGdsb2JhbCAlPiUgCiAgbXV0YXRlKHdlZWtkYXkgPSB3ZGF5KG9yZGVyX2RhdGUsIGxhYmVsID0gVCksCiAgICAgICAgZGF5ID0gZGF5KG9yZGVyX2RhdGUpLAogICAgICAgIG1vbnRoID0gbW9udGgob3JkZXJfZGF0ZSwgbGFiZWwgPSBUKSwKICAgICAgICB5ZWFyID0geWVhcihvcmRlcl9kYXRlKSkKYGBgCgpgYGB7cn0KZ2xvYmFsCmBgYAoKCiMjI0RldmlhdGlvbiAKIyMjI0RldmlhdGlvbiBjYW4gYmUgdXNlZCB0byBlbXBoYXNpemUgdmFyaWF0aW9uIGZyb20gYSBmaXhlZCByZWZlcmVuY2UgcG9pbnQgc3VjaCBhcyAwLCBhdmVyYWdlIG9yIGFueSB0YXJnZXQuIApgYGB7cn0KZGl2ZXJnaW5nX3Byb2ZpdCA9Cmdsb2JhbCAlPiUKICBtdXRhdGUoZ2Fpbl9sb3NzID0gaWZlbHNlKHByb2ZpdCA8IDAsICdsb3NzJywgJ2dhaW4nKSkgJT4lCiAgc2VsZWN0KG9yZGVyX2RhdGUsIHJlZ2lvbiwgcHJvZml0LCBnYWluX2xvc3MpICU+JQogIGFycmFuZ2UocHJvZml0KQoKICBnZ3Bsb3QoZGl2ZXJnaW5nX3Byb2ZpdCwgYWVzKHggPSByZWdpb24sIHkgPSBwcm9maXQsIGxhYmVsID0gcHJvZml0KSkgKwogIGdlb21fYmFyKHN0YXQ9J2lkZW50aXR5JywgYWVzKGZpbGw9Z2Fpbl9sb3NzKSwgd2lkdGg9LjgpICsgCiAgbGFicyh0aXRsZSA9ICJEaXZlcmdpbmcgQmFyIiwgc3VidGl0bGUgPSAiUHJvZml0IGxvc3Mgb3IgZ2FpbiBmcm9tIGEgZml4ZWQgcmVmZXJlbmNlIHBvaW50IG9mIDAiKSsKICBjb29yZF9mbGlwKCkrCiAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gYygiZ2FpbiI9IiMxRjc3QjQiLCAibG9zcyI9IiNGRjdGMEUiKSkKCmBgYAoKCmBgYHtyfQpnZ3Bsb3QoZGl2ZXJnaW5nX3Byb2ZpdCwgYWVzKHg9cmVnaW9uLCB5PXByb2ZpdCwgbGFiZWw9cHJvZml0KSkgKyAKICBnZW9tX3BvaW50KHN0YXQ9J2lkZW50aXR5JywgYWVzKGNvbG91cj1nYWluX2xvc3MpLCBzaXplPTIsIGFscGhhID0gMC42KSArICAKICBsYWJzKHRpdGxlID0gIkRpdmVyZ2luZyBEb3QgUGxvdCIsIAogICAgICAgc3VidGl0bGUgPSAiUHJvZml0IGxvc3Mgb3IgZ2FpbiBmcm9tIGEgZml4ZWQgcmVmZXJlbmNlIHBvaW50IG9mIDAiKSArIAogIGNvb3JkX2ZsaXAoKSArIHNjYWxlX2NvbG91cl9tYW51YWwodmFsdWVzID0gYygiZ2FpbiI9IiMxRjc3QjQiLCAibG9zcyI9IiNGRjdGMEUiKSkKCmBgYAoKCmBgYHtyfQpmaWx0ZXJfMjAxMiA9IGdsb2JhbCAlPiUgCiAgbXV0YXRlKGdhaW5fbG9zcyA9IGlmZWxzZShwcm9maXQgPiAwLCAnZ2FpbicsICdsb3NzJykpICU+JQogIGZpbHRlcihvcmRlcl9kYXRlIDwgIjIwMTEtMDYtMDEiKQogIApnZ3Bsb3QoZmlsdGVyXzIwMTIsIGFlcyhvcmRlcl9kYXRlLCBwcm9maXQsIGZpbGwgPSBnYWluX2xvc3MgKSkgKwogIGdlb21fYXJlYSgpICsgbGFicyh0aXRsZSA9ICJEaXZlcmdpbmcgQXJlYSBDaGFydCIsIHN1YnRpdGxlID0gIlByb2ZpdCBsb3NzIG9yIGdhaW4gZnJvbSBhIGZpeGVkIHJlZmVyZW5jZSBwb2ludCBvZiAwIikgKyBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXMgPSBjKCJnYWluIj0iIzFGNzdCNCIsICJsb3NzIj0iI0ZGN0YwRSIpKQpgYGAKCgojIyNDb3JyZWxhdGlvbgojIyMjQ29ycmVsYXRpb24gc2hvd3MgdGhlIHJlbGF0aW9uc2hpcCBiZXR3ZWVuIHR3byBvciBtb3JlIHZhcmlhYmxlcy4KYGBge3J9CmdncGxvdChnbG9iYWwsIGFlcyh4ID0gc2FsZXMsIHkgPSBwcm9maXQpKSArIAogIGdlb21fcG9pbnQoYWVzKGNvbCA9IHNlZ21lbnQpLCBhbHBoYSA9IDAuNikgKwogIGdlb21fc21vb3RoKG1ldGhvZCA9ICJsb2VzcyIsIHNlID0gRikgKyAKICBsYWJzKHRpdGxlID0gIlNjYXR0ZXJwbG90IHdpdGggU21vb3RoaW5nIExpbmUgQmFzZWQgb24gTE9FU1MiLCBzdWJ0aXRsZSA9ICJTYWxlcyB2cyBQcm9maXQiKSArCiAgc2NhbGVfY29sb3VyX21hbnVhbCh2YWx1ZXMgPSBjKCIjMUY3N0I0IiwiI0ZGN0YwRSIsICIjMkNBMDJDIikpCgpgYGAKCgojIyMjIExvYWRpbmcgZnVlbCBlY29ub215IGRhdGEgZnJvbSAxOTk5IGFuZCAyMDA4IGZvciAzOCBwb3B1bGFyIG1vZGVscyBvZiBjYXIKYGBge3J9Cm1wZwpgYGAKCgpgYGB7cn0KIGdncGxvdChtcGcsIGFlcyh4ID0gaHd5LCB5ID0gZGlzcGwpKSArCiAgZ2VvbV9wb2ludChjb2xvdXIgPSAiI0ZGN0YwRSIpKyAKICBnZW9tX3Ntb290aChtZXRob2QgPSAibG9lc3MiLCBzZSA9IEYpICsgCiAgbGFicyh0aXRsZSA9ICJTY2F0dGVycGxvdCB3aXRoIFNtb290aGluZyBMaW5lIEJhc2VkIG9uIExPRVNTIiwgc3VidGl0bGUgPSAiRW5naW5lIERpc3BsYWNlbWVudCB2cyBIaWdod2F5IE1pbGVzIFBlciBHYWxsb24iKQpgYGAKCgojIyMgUmFua2luZwojIyMjUmFua2luZyBpcyB1c2VmdWwgd2hlcmUgb3JkZXJlZCBsaXN0IGlzIGltcG9ydGFudC4KYGBge3J9CnJhbmtlZF9yZWdpb24gPSAKICBnbG9iYWwgJT4lIAogIHNlbGVjdChyZWdpb24sIHNhbGVzKSU+JQogIGdyb3VwX2J5KHJlZ2lvbikgJT4lCiAgc3VtbWFyaXNlKHN1bSA9IHN1bShzYWxlcykpICU+JQogIG11dGF0ZShyZWdpb24gPSBmYWN0b3IocmVnaW9uLCBsZXZlbHMgPSByZWdpb25bb3JkZXIoc3VtLCBkZWNyZWFzaW5nID0gVFJVRSldKSkKICAKZ2dwbG90KHJhbmtlZF9yZWdpb24sIGFlcyh4ID0gcmVnaW9uLCB5ID0gc3VtKSkgKwogIGdlb21fYmFyKHN0YXQgPSAiaWRlbnRpdHkiLCB3aWR0aCA9IC44LCBmaWxsID0gIiMxRjc3QjQiKSsgCiAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGU9NjUsIHZqdXN0PTAuNikpICsKICBsYWJzKHRpdGxlID0gIlJhbmtlZCBCYXIgQ2hhcnQiLCBzdWJ0aXRsZSA9ICJTYWxlcyBieSBSZWdpb24iKSAKICAKYGBgCgoKYGBge3J9CmdncGxvdChyYW5rZWRfcmVnaW9uLCBhZXMoeCA9IHJlZ2lvbiwgeSA9IHN1bSkpICsKICBnZW9tX3BvaW50KHNpemUgPSAzLCBjb2wgPSAiIzFGNzdCNCIsIGFscGhhID0gMC45KSsKICBnZW9tX3NlZ21lbnQoYWVzKHggPSByZWdpb24sIAogICAgICAgICAgICAgICB4ZW5kID0gcmVnaW9uLAogICAgICAgICAgICAgICB5ID0gbWluKHN1bSksCiAgICAgICAgICAgICAgIHllbmQgPSBtYXgoc3VtKSksCiAgICAgICAgICAgICAgbGluZXR5cGUgPSAiZGFzaGVkIiwKICAgICAgICAgICAgICBzaXplID0gMC4xKSArIAogIGxhYnModGl0bGUgPSAiRG90IFBsb3QgUmFua2luZyBCYXIiLCBzdWJ0aXRsZSA9ICJTYWxlcyB2cyBSZWdpb24iKSArCiAgY29vcmRfZmxpcCgpCmBgYAoKIyMjRGlzdHJpYnV0aW9uCkRpc3RyaWJ1dGlvbiBwbG90cyBzaG93IGhvdyBvZnRlbiB2YWx1ZXMgb2YgYSB2YXJpYWJsZSBvY2N1ci4KYGBge3J9CmdncGxvdChtcGcsIGFlcyh4ID0gaHd5KSkgKyAKICBnZW9tX2hpc3RvZ3JhbShiaW5zID0gNyxjb2wgPSAiYmxhY2siLCBmaWxsID0gIiMxRjc3QjQiKSArCiAgbGFicyh0aXRsZSA9ICJIaXN0b2dyYW0iLCBzdWJ0aXRsZSA9ICJDb3VudCBvZiBIaWdod2F5IE1pbGVzIikgCmBgYAoKIyMjIyBEYXRhIG11bmdpbmcKYGBge3J9Cm10Y2FycyRjeWwgPSBhcy5mYWN0b3IobXRjYXJzJGN5bCkKbXRjYXJzCmBgYAoKCmBgYHtyfQpnZ3Bsb3QobXRjYXJzLCBhZXMod3QpKSArIAogIGdlb21fZGVuc2l0eShhZXMoZmlsbCA9IGZhY3RvcihjeWwpKSwgYWxwaGEgPSAwLjcpICsgeGxpbSgwLDYpKwogIGxhYnModGl0bGU9IkRlbnNpdHkgcGxvdCIsIAogICAgICAgICBzdWJ0aXRsZT0iV2VpZ2h0ICgxMDAwIGxicykgcGVyIEN5bGluZGVyIiwKICAgICAgICAgY2FwdGlvbj0iU291cmNlOiBtdGNhcnMiLAogICAgICAgICB4PSJXZWlnaHQiLAogICAgICAgICBmaWxsPSJDeWxpbmRlcnMiKSArIAogIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IGMoIiMxRjc3QjQiLCAiIzJDQTAyQyIsIiNGRjdGMEUiKSkKCmBgYAoKYGBge3J9CmdncGxvdChtdGNhcnMsIGFlcyhjeWwsIHFzZWMsIGdyb3VwID0gY3lsKSkgKwogIGdlb21fYm94cGxvdCh2YXJ3aWR0aCA9IFQsIGZpbGwgPSAiIzFGNzdCNCIpICsKICBsYWJzKHRpdGxlPSJCb3hwbG90IiwgCiAgICAgICAgIHN1YnRpdGxlPSIxLzQgbWlsZSB0aW1lIHBlciBDeWxpbmRlciIsCiAgICAgICAgIGNhcHRpb249IlNvdXJjZTogbXRjYXJzIiwKICAgICAgICAgeD0iQ3lsaW5kZXJzIikKYGBgCgoKIyMjQ29tcG9zaXRpb24gCiMjIyMgQ29tcG9zaXRpb25zIGdyYXBocyBzaG93IGhvdyBhIHNpbmdsZSBlbnRpdHkgY2FuIGJlIGJyb2tlbiBkb3duIGludG8gaXRzIGNvbXBvbmVudHMgZWxlbWVudHMuIApgYGB7cn0KZ2dwbG90KGdsb2JhbCwgYWVzKHN1Yl9jYXRlZ29yeSkpICsKICBnZW9tX2JhcihhZXMoZmlsbCA9IGNhdGVnb3J5KSkgKwogIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlPTY1LCB2anVzdD0wLjYpKSArCiAgIGxhYnModGl0bGU9IkNvbXBvc2l0aW9uIiwgCiAgICAgICAgIHN1YnRpdGxlPSJDb3VudHMgb2YgU3ViLUNhdGVnb3J5IC0gR3JvdXBlZCBieSBDYXRlZ29yeSIsCiAgICAgICAgIGNhcHRpb249IlNvdXJjZTogU3VwZXJzdG9yZSIsCiAgICAgICAgIHg9IlN1Yi1DYXRlZ29yeSIsCiAgICAgICAgIGZpbGwgPSAiQ2F0ZWdvcnkiICkgKwogIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IGMoIiMxRjc3QjQiLCIjRkY3RjBFIiwgIiMyQ0EwMkMiKSkKICAKYGBgCmBgYHtyfQpnbG9iYWwKYGBgCgoKU3RhY2tlZCBDb2x1bW4KYGBge3J9CmdncGxvdChnbG9iYWwsIGFlcyhtYXJrZXQpKSArCiAgZ2VvbV9iYXIoYWVzKGZpbGwgPSBjYXRlZ29yeSkpICsgCiAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGU9NjUsIHZqdXN0PTAuNikpICsKICBsYWJzKHRpdGxlPSJDYXRlZ29yeSBTdGFja2VkIC0gQmFyIENoYXJ0IiwgCiAgICAgICBzdWJ0aXRsZT0iTWFya2V0cyAtIEdyb3VwZWQgYnkgQ2F0ZWdvcnkiLCAKICAgICAgIHggPSAiTWFya2V0IiwKICAgICAgIGZpbGwgPSAiQ2F0ZWdvcnkiLAogICAgICAgY2FwdGlvbj0iU291cmNlOiBTdXBlcnN0b3JlIikgKwogIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IGMoIiMxRjc3QjQiLCIjRkY3RjBFIiwgIiMyQ0EwMkMiKSkKYGBgCgoKYGBge3J9IApnbG9iYWxfdHJlZW1hcCA9IGdsb2JhbCAlPiUKICBmaWx0ZXIoeWVhciA9PSAyMDEyLCBtb250aCA9PSAnSmFuJykgJT4lCiAgbXV0YXRlKGNvdW50cnkgPSBhcy5mYWN0b3IoY291bnRyeSksCiAgICAgICAgICByZWdpb24gPSBhcy5mYWN0b3IocmVnaW9uKSwKICAgICAgICAgbWFya2V0ID0gYXMuZmFjdG9yKG1hcmtldCkpCgpsaWJyYXJ5KHRyZWVtYXBpZnkpCnRyZWVNYXBDb29yZGluYXRlcyA8LSB0cmVlbWFwaWZ5KAogIGdsb2JhbF90cmVlbWFwLAogIGFyZWEgPSAic2FsZXMiLAogIGZpbGwgPSAicHJvZml0IiwKICBncm91cCA9ICJtYXJrZXQiKQp0cmVlTWFwUGxvdCA8LSBnZ3Bsb3RpZnkodHJlZU1hcENvb3JkaW5hdGVzKQpwcmludCh0cmVlTWFwUGxvdCkKYGBgCgoKIyMjIENoYW5nZSAKIyMjI0NoYW5nZSBnaXZlcyBlbXBoYXNpcyB0byBjaGFuZ2luZyB0cmVuZHMuICAKYGBge3J9CnllYXJfMjAxMiA9IAogIGdsb2JhbCAlPiUgCiAgZmlsdGVyKHllYXIgPT0gMjAxMikKICBnZ3Bsb3QoeWVhcl8yMDEyLCBhZXMob3JkZXJfZGF0ZSwgc2FsZXMpKSArIAogICAgZ2VvbV9saW5lKGNvbCA9ICIjMUY3N0I0IikgKyAKICAgIGZhY2V0X3dyYXAofnNlZ21lbnQsIG5yb3cgPSAzKSArCiAgICBsYWJzKHRpdGxlPSJDaGFuZ2UgVHJlbmRzIiwgCiAgICAgICBzdWJ0aXRsZT0iU2FsZXMgYnkgc2VnbWVudCIsIAogICAgICAgeCA9ICJEYXRlIiwKICAgICAgIGNhcHRpb249IlNvdXJjZTogU3VwZXJzdG9yZSIpCmBgYAoKIyMjIyBIZWF0bWFwIC0gd2l0aCBoZWF0bWFwcyB3ZSBjYW4gc3BvdCB2YXJpYXRpb25zIG9mIGEgbWV0cmljLgpgYGB7cn0KbGlicmFyeShzdXBlcmhlYXQpCnN1cGVyaGVhdChtdGNhcnNfbWF0cml4LAogICAgICAgICAgbGVmdC5sYWJlbC5zaXplID0gMC4zLAogICAgICAgICAgbGVmdC5sYWJlbC50ZXh0LnNpemUgPSAzLAogICAgICAgICAgbGVnZW5kLnRleHQuc2l6ZSA9IDEyLAogICAgICAgICAgcGFkZGluZyA9IC4xKQpgYGAKCgoqKioKW1ZpZGVvIC0gMjMgVmlzdWFsaXphdGlvbnMgYW5kIHdoZW4gdG8gdXNlIHRoZW1dKGh0dHBzOi8vYmxvZy5kb21pbm9kYXRhbGFiLmNvbS92aWRlby0yMy12aXN1YWxpemF0aW9ucy11c2UvKQ==